#include "common.h"
#include "hash.h"

Hash* g_pHash = NULL;
//创建Hash表
Hash* CreateHash() {
	Hash* p = (Hash*)malloc(sizeof(Hash));
	memset(p, 0, sizeof(Hash));
	return p;
}
//销毁Hash表
void DestroyHash(Hash* pHash) {
	if (pHash == NULL) {
		return;
	}
	int i;
	for (i = 0; i < HASH_SIZE; i++) {
		Node* pCurrent = pHash->table[i];
		Node* pNext;
		while (pCurrent != NULL) {
			pNext = pCurrent->pNext;
			free(pCurrent);
			pCurrent = pNext;
		}
	}
	free(pHash);
}
// 向Hash表中插入数据
int InsertItem(Hash* pHash, data_t stInfo) {
	if (pHash == NULL) {
		return SYS_ERROR;
	}
	int index = stInfo->strDevice[0] % HASH_SIZE;
	while (pHash->table[index] != NULL) {
		index = (index + 1) % HASH_SIZE;
	}
	Node* pNewNode = (Node*)malloc(sizeof(Node));
	if (pNewNode == NULL) {
		return SYS_ERROR;
	}
	pNewNode->data = *stInfo;
	pNewNode->pNext = NULL;
	pHash->table[index] = pNewNode;//将新结点插入链表头部
	return SYS_OK;
}
//Hash表删除数据
int DeleteItem(Hash* pHash, data_t tData) {
	if (pHash == NULL || tData == NULL) return SYS_ERROR;

	int index = tData->strDevice[0] % HASH_SIZE;
	int probeCount = 0;
	int startIndex = index;

	while (probeCount < HASH_SIZE) { // 遍历所有桶
		Node* curr = pHash->table[index];
		if (curr == NULL) { // 空桶，未找到
			return SYS_ERROR;
		}
		// 匹配iFd和设备ID
		if (strcmp(curr->data.strDevice, tData->strDevice) == 0) {
			free(curr); // 释放节点
			pHash->table[index] = NULL; // 清空桶
			return SYS_OK;
		}
		// 线性探测下一个桶
		index = (index + 1) % HASH_SIZE;
		probeCount++;
	}
	return SYS_ERROR; // 遍历所有桶后未找到
}



//修改Hash表中的元素
int UpdateItem(Hash* pHash, data_t tData) {
	if (pHash == NULL) {
		return SYS_ERROR;
	}
	int index = tData->strDevice[0] % HASH_SIZE;
	int probeCount = 0;
	while (probeCount < HASH_SIZE) {
		Node* curr = pHash->table[index];
		while (curr != NULL) {
			if (strcmp(curr->data.strDevice, tData->strDevice) == 0) {
				// 更新现有节点的数据
				curr->data = *tData;
				return SYS_OK;
			}
			curr = curr->pNext;
		}

		// 线性探测下一个桶
		index = (index + 1) % HASH_SIZE;
		probeCount++;
	}

	return SYS_ERROR; // 未找到匹配的设备ID
}

//根据设备ID返回设备的文件描述符
int FindFdFromHash(Hash* pHash, char* dev_id) {
	if (pHash == NULL) {
		return SYS_ERROR;
	}
	for (int i = 0; i < HASH_SIZE; i++) {
		Node* tmp = pHash->table[i];
		while (tmp != NULL) {
			if (strcmp(tmp->data.strDevice, dev_id) == 0) {
				return tmp->data.iFd; // 找到并返回文件描述符
			}
			tmp = tmp->pNext;
		}
	}
	return SYS_ERROR; // 未找到匹配的设备 ID
}
//在hash表中查找指定的设备信息
int FindDevice(Hash* pHash, data_t tData, int* pOldFd) {
	int i;
	for (i = 0; i < HASH_SIZE; i++) {
		Node* tmp = pHash->table[i];
		while(tmp!=NULL){
			if (strcmp(tmp->data.strDevice, tData->strDevice) == 0) {
				if (tmp->data.iFd != tData->iFd || (tData->lTime - tmp->data.lTime) > 10 * 60) {
					*pOldFd = tmp->data.iFd;//记录旧的文件描述符
					UpdateItem(pHash, tData); // 更新设备时间信息
					return SYS_DEVICE_REINSERT; // 需要重新插入新的设备信息
				}
				else {// 时间未超时，更新设备信息时间
					tmp->data.lTime = tData->lTime;
					return SYS_OK;
				}
			}
			tmp = tmp->pNext;
		}
	}
	return SYS_ERROR; // 未找到设备信息
}
//显示Hash表信息
void ShowHash(Hash* pHash) {
	if (pHash == NULL) {
		printf("hash表不存在\n");
		return;
	}
	int i;
	for (i = 0; i < HASH_SIZE; i++) {
		Node* tmp = pHash->table[i];
		while (tmp != NULL) {
			printf("iFd = %d, strDevice = %s, lTime = %ld\n",  tmp->data.iFd, tmp->data.strDevice, tmp->data.lTime);
			tmp = tmp->pNext;
		}
	}
}
//从Hash表中删除超时的设备信息
int DeleteTimeOutDevFromHash(Hash* pHash, fd_set* pSet, int iMax) {
	if (pHash == NULL || pSet == NULL) {
		return SYS_ERROR;
	}
	int i, j;
	for (i = 0; i < HASH_SIZE; i++) {
		Node* tmp = pHash->table[i];
		while (tmp != NULL) {
			if (FD_ISSET(tmp->data.iFd, pSet)) { // 判断fd是否在集合中，检查是否超时
				DeleteItem(pHash, &tmp->data); // 是则删除该设备信息
			}
			tmp = tmp->pNext; // 继续查找下一个节点，不是超时则继续处理
		}
	}
	// 更新 select 监听范围，最大文件描述符为 iMax
	for (j = 0; j < HASH_SIZE; j++) {
		i = j; // 线性探测下一个桶
		while (pHash->table[i] != NULL) {
			i = (i + 1) % HASH_SIZE;
		}
	}
	return (i > iMax ? SYS_UPDATE_MAX_FD : SYS_OK); // 是否需要更新监听范围
}
